using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class InterpolatedStringBuilderSpecification {
        [Test]
        public void ShouldBuildSimpleStringFromMultipleStringComponents () {
            var builder = new InterpolatedStringBuilder(10, CreateSourceInformation);

            builder.AddString ("one", 13);
            builder.AddString ("two", 16);

            var stringTerm = builder.CreateTerm (17) as StringTerm;

            Assert.IsNotNull (stringTerm);
            Assert.AreEqual ("onetwo", stringTerm.Value);
            Assert.AreEqual (new SourceInformation ("filename", 10, 7), stringTerm.SourceInformation);
        }

        [Test]
        public void ShouldBuildCompositeTermIfTermsAreAdded () {
            var builder = new InterpolatedStringBuilder (2, CreateSourceInformation);

            var term1 = new FakeTerm ();
            builder.AddTerm (term1, 5);
            var term2 = new FakeTerm ();
            builder.AddTerm (term2, 12);

            var compositeTerm = builder.CreateTerm (13) as CompositeTerm;

            Assert.IsNotNull (compositeTerm);
            Assert.AreEqual ("interpolated-string", compositeTerm.Name);
            Assert.AreEqual (1, compositeTerm.SubTerms.Count);
            var components = compositeTerm.SubTerms["components"] as ListTerm;
            Assert.IsNotNull (components);
            Assert.AreEqual (2, components.Terms.Count);
            Assert.AreEqual (term1, components.Terms[0]);
            Assert.AreEqual (term2, components.Terms[1]);

            Assert.AreEqual (new SourceInformation ("filename", 2, 11), compositeTerm.SourceInformation);
        }

        public class FakeTerm : Term {
            public FakeTerm () : base (null) {}
        }

        [Test]
        public void ShouldBuildCompositeTermWithBothStringsAndTerms () {
            var builder = new InterpolatedStringBuilder (1, CreateSourceInformation);

            builder.AddString ("one", 3);
            var term1 = new FakeTerm ();
            builder.AddTerm (term1, 6);
            var term2 = new FakeTerm ();
            builder.AddTerm (term2, 10);
            builder.AddString ("two", 14);

            var compositeTerm = builder.CreateTerm (20) as CompositeTerm;

            Assert.IsNotNull (compositeTerm);
            Assert.AreEqual ("interpolated-string", compositeTerm.Name);
            Assert.AreEqual (1, compositeTerm.SubTerms.Count);
            var components = compositeTerm.SubTerms["components"] as ListTerm;
            Assert.IsNotNull (components);
            Assert.AreEqual (4, components.Terms.Count);
            Assert.AreEqual ("one", ((StringTerm) components.Terms[0]).Value);
            Assert.AreEqual (new SourceInformation ("filename", 1, 2), components.Terms[0].SourceInformation);

            Assert.AreEqual (term1, components.Terms[1]);
            Assert.AreEqual (term2, components.Terms[2]);

            Assert.AreEqual ("two", ((StringTerm) components.Terms[3]).Value);
            Assert.AreEqual (new SourceInformation ("filename", 10, 4), components.Terms[3].SourceInformation);

            Assert.AreEqual (new SourceInformation ("filename", 1, 19), compositeTerm.SourceInformation);
        }

        private static SourceInformation CreateSourceInformation (int index, int length) {
            return new SourceInformation ("filename", index, length);
        }
    }
}